【题解】 [POI2007]ZAP-Queries 莫比乌斯反演 luogu3455 | Qiuly's blog!

【题解】 [POI2007]ZAP-Queries 莫比乌斯反演 luogu3455

很显然是让我们求出下式:

根据性质可以得到:

我们设两个函数:

  • 函数 $f$,$f(x)$ 表示 $\sum_{i=1}^{\lfloor\frac{A}{K}\rfloor}\sum_{j=1}^{\lfloor\frac{B}{K}\rfloor}[gcd(i,j)=x]$
  • 函数 $g$ ,$g(x)$ 表示 $\sum_{i=1}^{\lfloor\frac{A}{K}\rfloor}\sum_{j=1}^{\lfloor\frac{B}{K}\rfloor}[x|gcd(i,j)]$

我们可以得到:

这是莫比乌斯反演的第二个形式:

于是:

设 $n=\lfloor\frac{A}{K}\rfloor\ ,\ m=\lfloor\frac{B}{K}\rfloor$

那么:

这个式子是 $O(n)$ 的。

发现 $\lfloor\frac{A}{K}\rfloor \times\lfloor\frac{B}{K}\rfloor$ 可以整除分块,于是我们便可以做到 $O(\sqrt{x})$

Code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include<cmath>
#include<cstdio>
#include<iostream>
#include<algorithm>

const int N=1e5+2;
const int inf=1e9+9;

int T,cnt;
int prime[N],mui[N],vis[N];
long long sum[N];

inline int _Pre_mui(){
mui[1]=1;
for(int i=2;i<=N;++i){
if(!vis[i])prime[++cnt]=i,mui[i]=-1;
for(int j=1;j<=cnt;++j){
if(i*prime[j]>=N)break;
vis[i*prime[j]]=1;
if(!(i%prime[j])){mui[i*prime[j]]=0;break;}
else mui[i*prime[j]]=-mui[i];
}
}for(int i=1;i<=N;++i)sum[i]=sum[i-1]+mui[i];
return 0;
}

#define min(x,y) ((x)<(y)?(x):(y))

inline void solve(int n,int m,int k){
long long ans=0;
n/=k,m/=k;
int lim=min(n,m);
for(int i=1;i<=lim;){
long long j=min(n/(n/i),m/(m/i));
ans+=1ll*(sum[j]-sum[i-1])*(n/i)*(m/i);
i=j+1;
}printf("%lld\n",ans);
return;
}

int main(){
_Pre_mui();
scanf("%d",&T);
while(T--){
int n,m,k;
scanf("%d%d%d",&n,&m,&k);
solve(n,m,k);
}return 0;
}

所以就没了。

本文标题:【题解】 [POI2007]ZAP-Queries 莫比乌斯反演 luogu3455

文章作者:Qiuly

发布时间:2019年02月27日 - 00:00

最后更新:2019年03月29日 - 13:54

原始链接:http://qiulyblog.github.io/2019/02/27/[题解]luoguP3455/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。